home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / inetutil.1 / inetutil / inetutils-1.1 / libtelnet / enc_des.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-22  |  15.5 KB  |  729 lines

  1. /*-
  2.  * Copyright (c) 1991, 1993
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char sccsid[] = "@(#)enc_des.c    8.3 (Berkeley) 5/30/95";
  36. #endif /* not lint */
  37.  
  38. #ifdef HAVE_CONFIG_H
  39. #include <config.h>
  40. #endif
  41.  
  42. #ifdef    ENCRYPTION
  43. # ifdef    AUTHENTICATION
  44. #  ifdef DES_ENCRYPTION
  45. #include <arpa/telnet.h>
  46. #include <stdio.h>
  47. #ifdef    __STDC__
  48. #include <stdlib.h>
  49. #endif
  50.  
  51. #include "encrypt.h"
  52. #include "key-proto.h"
  53. #include "misc-proto.h"
  54.  
  55. extern encrypt_debug_mode;
  56.  
  57. #define    CFB    0
  58. #define    OFB    1
  59.  
  60. #define    NO_SEND_IV    1
  61. #define    NO_RECV_IV    2
  62. #define    NO_KEYID    4
  63. #define    IN_PROGRESS    (NO_SEND_IV|NO_RECV_IV|NO_KEYID)
  64. #define    SUCCESS        0
  65. #define    FAILED        -1
  66.  
  67.  
  68. struct fb {
  69.     Block krbdes_key;
  70.     Schedule krbdes_sched;
  71.     Block temp_feed;
  72.     unsigned char fb_feed[64];
  73.     int need_start;
  74.     int state[2];
  75.     int keyid[2];
  76.     int once;
  77.     struct stinfo {
  78.         Block        str_output;
  79.         Block        str_feed;
  80.         Block        str_iv;
  81.         Block        str_ikey;
  82.         Schedule    str_sched;
  83.         int        str_index;
  84.         int        str_flagshift;
  85.     } streams[2];
  86. };
  87.  
  88. static struct fb fb[2];
  89.  
  90. struct keyidlist {
  91.     char    *keyid;
  92.     int    keyidlen;
  93.     char    *key;
  94.     int    keylen;
  95.     int    flags;
  96. } keyidlist [] = {
  97.     { "\0", 1, 0, 0, 0 },        /* default key of zero */
  98.     { 0, 0, 0, 0, 0 }
  99. };
  100.  
  101. #define    KEYFLAG_MASK    03
  102.  
  103. #define    KEYFLAG_NOINIT    00
  104. #define    KEYFLAG_INIT    01
  105. #define    KEYFLAG_OK    02
  106. #define    KEYFLAG_BAD    03
  107.  
  108. #define    KEYFLAG_SHIFT    2
  109.  
  110. #define    SHIFT_VAL(a,b)    (KEYFLAG_SHIFT*((a)+((b)*2)))
  111.  
  112. #define    FB64_IV        1
  113. #define    FB64_IV_OK    2
  114. #define    FB64_IV_BAD    3
  115.  
  116.  
  117. void fb64_stream_iv P((Block, struct stinfo *));
  118. void fb64_init P((struct fb *));
  119. static int fb64_start P((struct fb *, int, int));
  120. int fb64_is P((unsigned char *, int, struct fb *));
  121. int fb64_reply P((unsigned char *, int, struct fb *));
  122. static void fb64_session P((Session_Key *, int, struct fb *));
  123. void fb64_stream_key P((Block, struct stinfo *));
  124. int fb64_keyid P((int, unsigned char *, int *, struct fb *));
  125.  
  126.     void
  127. cfb64_init(server)
  128.     int server;
  129. {
  130.     fb64_init(&fb[CFB]);
  131.     fb[CFB].fb_feed[4] = ENCTYPE_DES_CFB64;
  132.     fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, CFB);
  133.     fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, CFB);
  134. }
  135.  
  136.     void
  137. ofb64_init(server)
  138.     int server;
  139. {
  140.     fb64_init(&fb[OFB]);
  141.     fb[OFB].fb_feed[4] = ENCTYPE_DES_OFB64;
  142.     fb[CFB].streams[0].str_flagshift = SHIFT_VAL(0, OFB);
  143.     fb[CFB].streams[1].str_flagshift = SHIFT_VAL(1, OFB);
  144. }
  145.  
  146.     void
  147. fb64_init(fbp)
  148.     register struct fb *fbp;
  149. {
  150.     memset((void *)fbp, 0, sizeof(*fbp));
  151.     fbp->state[0] = fbp->state[1] = FAILED;
  152.     fbp->fb_feed[0] = IAC;
  153.     fbp->fb_feed[1] = SB;
  154.     fbp->fb_feed[2] = TELOPT_ENCRYPT;
  155.     fbp->fb_feed[3] = ENCRYPT_IS;
  156. }
  157.  
  158. /*
  159.  * Returns:
  160.  *    -1: some error.  Negotiation is done, encryption not ready.
  161.  *     0: Successful, initial negotiation all done.
  162.  *     1: successful, negotiation not done yet.
  163.  *     2: Not yet.  Other things (like getting the key from
  164.  *        Kerberos) have to happen before we can continue.
  165.  */
  166.     int
  167. cfb64_start(dir, server)
  168.     int dir;
  169.     int server;
  170. {
  171.     return(fb64_start(&fb[CFB], dir, server));
  172. }
  173.     int
  174. ofb64_start(dir, server)
  175.     int dir;
  176.     int server;
  177. {
  178.     return(fb64_start(&fb[OFB], dir, server));
  179. }
  180.  
  181.     static int
  182. fb64_start(fbp, dir, server)
  183.     struct fb *fbp;
  184.     int dir;
  185.     int server;
  186. {
  187.     Block b;
  188.     int x;
  189.     unsigned char *p;
  190.     register int state;
  191.  
  192.     switch (dir) {
  193.     case DIR_DECRYPT:
  194.         /*
  195.          * This is simply a request to have the other side
  196.          * start output (our input).  He will negotiate an
  197.          * IV so we need not look for it.
  198.          */
  199.         state = fbp->state[dir-1];
  200.         if (state == FAILED)
  201.             state = IN_PROGRESS;
  202.         break;
  203.  
  204.     case DIR_ENCRYPT:
  205.         state = fbp->state[dir-1];
  206.         if (state == FAILED)
  207.             state = IN_PROGRESS;
  208.         else if ((state & NO_SEND_IV) == 0)
  209.             break;
  210.  
  211.         if (!VALIDKEY(fbp->krbdes_key)) {
  212.             fbp->need_start = 1;
  213.             break;
  214.         }
  215.         state &= ~NO_SEND_IV;
  216.         state |= NO_RECV_IV;
  217.         if (encrypt_debug_mode)
  218.             printf("Creating new feed\r\n");
  219.         /*
  220.          * Create a random feed and send it over.
  221.          */
  222.         des_new_random_key(fbp->temp_feed);
  223.         des_ecb_encrypt(fbp->temp_feed, fbp->temp_feed,
  224.                 fbp->krbdes_sched, 1);
  225.         p = fbp->fb_feed + 3;
  226.         *p++ = ENCRYPT_IS;
  227.         p++;
  228.         *p++ = FB64_IV;
  229.         for (x = 0; x < sizeof(Block); ++x) {
  230.             if ((*p++ = fbp->temp_feed[x]) == IAC)
  231.                 *p++ = IAC;
  232.         }
  233.         *p++ = IAC;
  234.         *p++ = SE;
  235.         printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
  236.         net_write(fbp->fb_feed, p - fbp->fb_feed);
  237.         break;
  238.     default:
  239.         return(FAILED);
  240.     }
  241.     return(fbp->state[dir-1] = state);
  242. }
  243.  
  244. /*
  245.  * Returns:
  246.  *    -1: some error.  Negotiation is done, encryption not ready.
  247.  *     0: Successful, initial negotiation all done.
  248.  *     1: successful, negotiation not done yet.
  249.  */
  250.     int
  251. cfb64_is(data, cnt)
  252.     unsigned char *data;
  253.     int cnt;
  254. {
  255.     return(fb64_is(data, cnt, &fb[CFB]));
  256. }
  257.     int
  258. ofb64_is(data, cnt)
  259.     unsigned char *data;
  260.     int cnt;
  261. {
  262.     return(fb64_is(data, cnt, &fb[OFB]));
  263. }
  264.  
  265.     int
  266. fb64_is(data, cnt, fbp)
  267.     unsigned char *data;
  268.     int cnt;
  269.     struct fb *fbp;
  270. {
  271.     int x;
  272.     unsigned char *p;
  273.     Block b;
  274.     register int state = fbp->state[DIR_DECRYPT-1];
  275.  
  276.     if (cnt-- < 1)
  277.         goto failure;
  278.  
  279.     switch (*data++) {
  280.     case FB64_IV:
  281.         if (cnt != sizeof(Block)) {
  282.             if (encrypt_debug_mode)
  283.                 printf("CFB64: initial vector failed on size\r\n");
  284.             state = FAILED;
  285.             goto failure;
  286.         }
  287.  
  288.         if (encrypt_debug_mode)
  289.             printf("CFB64: initial vector received\r\n");
  290.  
  291.         if (encrypt_debug_mode)
  292.             printf("Initializing Decrypt stream\r\n");
  293.  
  294.         fb64_stream_iv((void *)data, &fbp->streams[DIR_DECRYPT-1]);
  295.  
  296.         p = fbp->fb_feed + 3;
  297.         *p++ = ENCRYPT_REPLY;
  298.         p++;
  299.         *p++ = FB64_IV_OK;
  300.         *p++ = IAC;
  301.         *p++ = SE;
  302.         printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
  303.         net_write(fbp->fb_feed, p - fbp->fb_feed);
  304.  
  305.         state = fbp->state[DIR_DECRYPT-1] = IN_PROGRESS;
  306.         break;
  307.  
  308.     default:
  309.         if (encrypt_debug_mode) {
  310.             printf("Unknown option type: %d\r\n", *(data-1));
  311.             printd(data, cnt);
  312.             printf("\r\n");
  313.         }
  314.         /* FALL THROUGH */
  315.     failure:
  316.         /*
  317.          * We failed.  Send an FB64_IV_BAD option
  318.          * to the other side so it will know that
  319.          * things failed.
  320.          */
  321.         p = fbp->fb_feed + 3;
  322.         *p++ = ENCRYPT_REPLY;
  323.         p++;
  324.         *p++ = FB64_IV_BAD;
  325.         *p++ = IAC;
  326.         *p++ = SE;
  327.         printsub('>', &fbp->fb_feed[2], p - &fbp->fb_feed[2]);
  328.         net_write(fbp->fb_feed, p - fbp->fb_feed);
  329.  
  330.         break;
  331.     }
  332.     return(fbp->state[DIR_DECRYPT-1] = state);
  333. }
  334.  
  335. /*
  336.  * Returns:
  337.  *    -1: some error.  Negotiation is done, encryption not ready.
  338.  *     0: Successful, initial negotiation all done.
  339.  *     1: successful, negotiation not done yet.
  340.  */
  341.     int
  342. cfb64_reply(data, cnt)
  343.     unsigned char *data;
  344.     int cnt;
  345. {
  346.     return(fb64_reply(data, cnt, &fb[CFB]));
  347. }
  348.     int
  349. ofb64_reply(data, cnt)
  350.     unsigned char *data;
  351.     int cnt;
  352. {
  353.     return(fb64_reply(data, cnt, &fb[OFB]));
  354. }
  355.  
  356.  
  357.     int
  358. fb64_reply(data, cnt, fbp)
  359.     unsigned char *data;
  360.     int cnt;
  361.     struct fb *fbp;
  362. {
  363.     int x;
  364.     unsigned char *p;
  365.     Block b;
  366.     register int state = fbp->state[DIR_ENCRYPT-1];
  367.  
  368.     if (cnt-- < 1)
  369.         goto failure;
  370.  
  371.     switch (*data++) {
  372.     case FB64_IV_OK:
  373.         fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
  374.         if (state == FAILED)
  375.             state = IN_PROGRESS;
  376.         state &= ~NO_RECV_IV;
  377.         encrypt_send_keyid(DIR_ENCRYPT, (unsigned char *)"\0", 1, 1);
  378.         break;
  379.  
  380.     case FB64_IV_BAD:
  381.         memset(fbp->temp_feed, 0, sizeof(Block));
  382.         fb64_stream_iv(fbp->temp_feed, &fbp->streams[DIR_ENCRYPT-1]);
  383.         state = FAILED;
  384.         break;
  385.  
  386.     default:
  387.         if (encrypt_debug_mode) {
  388.             printf("Unknown option type: %d\r\n", data[-1]);
  389.             printd(data, cnt);
  390.             printf("\r\n");
  391.         }
  392.         /* FALL THROUGH */
  393.     failure:
  394.         state = FAILED;
  395.         break;
  396.     }
  397.     return(fbp->state[DIR_ENCRYPT-1] = state);
  398. }
  399.  
  400.     void
  401. cfb64_session(key, server)
  402.     Session_Key *key;
  403.     int server;
  404. {
  405.     fb64_session(key, server, &fb[CFB]);
  406. }
  407.  
  408.     void
  409. ofb64_session(key, server)
  410.     Session_Key *key;
  411.     int server;
  412. {
  413.     fb64_session(key, server, &fb[OFB]);
  414. }
  415.  
  416.     static void
  417. fb64_session(key, server, fbp)
  418.     Session_Key *key;
  419.     int server;
  420.     struct fb *fbp;
  421. {
  422.  
  423.     if (!key || key->type != SK_DES) {
  424.         if (encrypt_debug_mode)
  425.             printf("Can't set krbdes's session key (%d != %d)\r\n",
  426.                 key ? key->type : -1, SK_DES);
  427.         return;
  428.     }
  429.     memmove((void *)fbp->krbdes_key, (void *)key->data, sizeof(Block));
  430.  
  431.     fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_ENCRYPT-1]);
  432.     fb64_stream_key(fbp->krbdes_key, &fbp->streams[DIR_DECRYPT-1]);
  433.  
  434.     if (fbp->once == 0) {
  435.         des_set_random_generator_seed(fbp->krbdes_key);
  436.         fbp->once = 1;
  437.     }
  438.     des_key_sched(fbp->krbdes_key, fbp->krbdes_sched);
  439.     /*
  440.      * Now look to see if krbdes_start() was was waiting for
  441.      * the key to show up.  If so, go ahead an call it now
  442.      * that we have the key.
  443.      */
  444.     if (fbp->need_start) {
  445.         fbp->need_start = 0;
  446.         fb64_start(fbp, DIR_ENCRYPT, server);
  447.     }
  448. }
  449.  
  450. /*
  451.  * We only accept a keyid of 0.  If we get a keyid of
  452.  * 0, then mark the state as SUCCESS.
  453.  */
  454.     int
  455. cfb64_keyid(dir, kp, lenp)
  456.     int dir, *lenp;
  457.     unsigned char *kp;
  458. {
  459.     return(fb64_keyid(dir, kp, lenp, &fb[CFB]));
  460. }
  461.  
  462.     int
  463. ofb64_keyid(dir, kp, lenp)
  464.     int dir, *lenp;
  465.     unsigned char *kp;
  466. {
  467.     return(fb64_keyid(dir, kp, lenp, &fb[OFB]));
  468. }
  469.  
  470.     int
  471. fb64_keyid(dir, kp, lenp, fbp)
  472.     int dir, *lenp;
  473.     unsigned char *kp;
  474.     struct fb *fbp;
  475. {
  476.     register int state = fbp->state[dir-1];
  477.  
  478.     if (*lenp != 1 || (*kp != '\0')) {
  479.         *lenp = 0;
  480.         return(state);
  481.     }
  482.  
  483.     if (state == FAILED)
  484.         state = IN_PROGRESS;
  485.  
  486.     state &= ~NO_KEYID;
  487.  
  488.     return(fbp->state[dir-1] = state);
  489. }
  490.  
  491.     void
  492. fb64_printsub(data, cnt, buf, buflen, type)
  493.     unsigned char *data, *buf, *type;
  494.     int cnt, buflen;
  495. {
  496.     char lbuf[32];
  497.     register int i;
  498.     char *cp;
  499.  
  500.     buf[buflen-1] = '\0';        /* make sure it's NULL terminated */
  501.     buflen -= 1;
  502.  
  503.     switch(data[2]) {
  504.     case FB64_IV:
  505.         sprintf(lbuf, "%s_IV", type);
  506.         cp = lbuf;
  507.         goto common;
  508.  
  509.     case FB64_IV_OK:
  510.         sprintf(lbuf, "%s_IV_OK", type);
  511.         cp = lbuf;
  512.         goto common;
  513.  
  514.     case FB64_IV_BAD:
  515.         sprintf(lbuf, "%s_IV_BAD", type);
  516.         cp = lbuf;
  517.         goto common;
  518.  
  519.     default:
  520.         sprintf(lbuf, " %d (unknown)", data[2]);
  521.         cp = lbuf;
  522.     common:
  523.         for (; (buflen > 0) && (*buf = *cp++); buf++)
  524.             buflen--;
  525.         for (i = 3; i < cnt; i++) {
  526.             sprintf(lbuf, " %d", data[i]);
  527.             for (cp = lbuf; (buflen > 0) && (*buf = *cp++); buf++)
  528.                 buflen--;
  529.         }
  530.         break;
  531.     }
  532. }
  533.  
  534.     void
  535. cfb64_printsub(data, cnt, buf, buflen)
  536.     unsigned char *data, *buf;
  537.     int cnt, buflen;
  538. {
  539.     fb64_printsub(data, cnt, buf, buflen, "CFB64");
  540. }
  541.  
  542.     void
  543. ofb64_printsub(data, cnt, buf, buflen)
  544.     unsigned char *data, *buf;
  545.     int cnt, buflen;
  546. {
  547.     fb64_printsub(data, cnt, buf, buflen, "OFB64");
  548. }
  549.  
  550.     void
  551. fb64_stream_iv(seed, stp)
  552.     Block seed;
  553.     register struct stinfo *stp;
  554. {
  555.  
  556.     memmove((void *)stp->str_iv, (void *)seed, sizeof(Block));
  557.     memmove((void *)stp->str_output, (void *)seed, sizeof(Block));
  558.  
  559.     des_key_sched(stp->str_ikey, stp->str_sched);
  560.  
  561.     stp->str_index = sizeof(Block);
  562. }
  563.  
  564.     void
  565. fb64_stream_key(key, stp)
  566.     Block key;
  567.     register struct stinfo *stp;
  568. {
  569.     memmove((void *)stp->str_ikey, (void *)key, sizeof(Block));
  570.     des_key_sched(key, stp->str_sched);
  571.  
  572.     memmove((void *)stp->str_output, (void *)stp->str_iv, sizeof(Block));
  573.  
  574.     stp->str_index = sizeof(Block);
  575. }
  576.  
  577. /*
  578.  * DES 64 bit Cipher Feedback
  579.  *
  580.  *     key --->+-----+
  581.  *          +->| DES |--+
  582.  *          |  +-----+  |
  583.  *        |           v
  584.  *  INPUT --(--------->(+)+---> DATA
  585.  *          |             |
  586.  *        +-------------+
  587.  *         
  588.  *
  589.  * Given:
  590.  *    iV: Initial vector, 64 bits (8 bytes) long.
  591.  *    Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
  592.  *    On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
  593.  *
  594.  *    V0 = DES(iV, key)
  595.  *    On = Dn ^ Vn
  596.  *    V(n+1) = DES(On, key)
  597.  */
  598.  
  599.     void
  600. cfb64_encrypt(s, c)
  601.     register unsigned char *s;
  602.     int c;
  603. {
  604.     register struct stinfo *stp = &fb[CFB].streams[DIR_ENCRYPT-1];
  605.     register int index;
  606.  
  607.     index = stp->str_index;
  608.     while (c-- > 0) {
  609.         if (index == sizeof(Block)) {
  610.             Block b;
  611.             des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1);
  612.             memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
  613.             index = 0;
  614.         }
  615.  
  616.         /* On encryption, we store (feed ^ data) which is cypher */
  617.         *s = stp->str_output[index] = (stp->str_feed[index] ^ *s);
  618.         s++;
  619.         index++;
  620.     }
  621.     stp->str_index = index;
  622. }
  623.  
  624.     int
  625. cfb64_decrypt(data)
  626.     int data;
  627. {
  628.     register struct stinfo *stp = &fb[CFB].streams[DIR_DECRYPT-1];
  629.     int index;
  630.  
  631.     if (data == -1) {
  632.         /*
  633.          * Back up one byte.  It is assumed that we will
  634.          * never back up more than one byte.  If we do, this
  635.          * may or may not work.
  636.          */
  637.         if (stp->str_index)
  638.             --stp->str_index;
  639.         return(0);
  640.     }
  641.  
  642.     index = stp->str_index++;
  643.     if (index == sizeof(Block)) {
  644.         Block b;
  645.         des_ecb_encrypt(stp->str_output, b, stp->str_sched, 1);
  646.         memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
  647.         stp->str_index = 1;    /* Next time will be 1 */
  648.         index = 0;        /* But now use 0 */ 
  649.     }
  650.  
  651.     /* On decryption we store (data) which is cypher. */
  652.     stp->str_output[index] = data;
  653.     return(data ^ stp->str_feed[index]);
  654. }
  655.  
  656. /*
  657.  * DES 64 bit Output Feedback
  658.  *
  659.  * key --->+-----+
  660.  *    +->| DES |--+
  661.  *    |  +-----+  |
  662.  *    +-----------+
  663.  *                v
  664.  *  INPUT -------->(+) ----> DATA
  665.  *
  666.  * Given:
  667.  *    iV: Initial vector, 64 bits (8 bytes) long.
  668.  *    Dn: the nth chunk of 64 bits (8 bytes) of data to encrypt (decrypt).
  669.  *    On: the nth chunk of 64 bits (8 bytes) of encrypted (decrypted) output.
  670.  *
  671.  *    V0 = DES(iV, key)
  672.  *    V(n+1) = DES(Vn, key)
  673.  *    On = Dn ^ Vn
  674.  */
  675.     void
  676. ofb64_encrypt(s, c)
  677.     register unsigned char *s;
  678.     int c;
  679. {
  680.     register struct stinfo *stp = &fb[OFB].streams[DIR_ENCRYPT-1];
  681.     register int index;
  682.  
  683.     index = stp->str_index;
  684.     while (c-- > 0) {
  685.         if (index == sizeof(Block)) {
  686.             Block b;
  687.             des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1);
  688.             memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
  689.             index = 0;
  690.         }
  691.         *s++ ^= stp->str_feed[index];
  692.         index++;
  693.     }
  694.     stp->str_index = index;
  695. }
  696.  
  697.     int
  698. ofb64_decrypt(data)
  699.     int data;
  700. {
  701.     register struct stinfo *stp = &fb[OFB].streams[DIR_DECRYPT-1];
  702.     int index;
  703.  
  704.     if (data == -1) {
  705.         /*
  706.          * Back up one byte.  It is assumed that we will
  707.          * never back up more than one byte.  If we do, this
  708.          * may or may not work.
  709.          */
  710.         if (stp->str_index)
  711.             --stp->str_index;
  712.         return(0);
  713.     }
  714.  
  715.     index = stp->str_index++;
  716.     if (index == sizeof(Block)) {
  717.         Block b;
  718.         des_ecb_encrypt(stp->str_feed, b, stp->str_sched, 1);
  719.         memmove((void *)stp->str_feed, (void *)b, sizeof(Block));
  720.         stp->str_index = 1;    /* Next time will be 1 */
  721.         index = 0;        /* But now use 0 */ 
  722.     }
  723.  
  724.     return(data ^ stp->str_feed[index]);
  725. }
  726. #  endif /* DES_ENCRYPTION */
  727. # endif    /* AUTHENTICATION */
  728. #endif    /* ENCRYPTION */
  729.